(C++)分支限界法求解背包问题

10 篇文章 0 订阅

1.beibao.h文件代码如下:

#ifndef BEIBAO_H
#define  BEIBAO_H

#include <math.h>


//子空间中节点类型
class BBnode{
public: 
	BBnode*  parent;   //父节点
	bool leftChild;   //左儿子节点标志
	BBnode(BBnode* par,bool ch){
		parent=par;
		leftChild=ch;
	}
	BBnode(){

	}
};

class HeapNode {
public:
	BBnode* liveNode; // 活结点
	double  upperProfit; //结点的价值上界
	double  profit; //结点所相应的价值
	double  weight; //结点所相应的重量
	int     level; // 活结点在子集树中所处的层次号

	//构造方法
	 HeapNode(BBnode* node, double up, double pp , double ww,int lev){
		liveNode = node;
		upperProfit = up;
		profit    = pp;
		weight    = ww;
		level    = lev;
	}
	 HeapNode(){

	 }
	 int compareTo(HeapNode o) {
		double xup =o.upperProfit;
		if(upperProfit < xup)
			return -1;
		if(upperProfit == xup)
			return 0;
		else
			return 1;
	}
};

class Element  {
public:
	int id;
	double d;
	Element(){

	}
	Element(int idd,double dd){
		id=idd;
		d=dd;
	}
	int compareTo(Element x){
		double xd=x.d;
		if(d<xd)return -1;
		if(d==xd)return 0;
		return 1;
	}
	 bool equals(Element x){
		return d==x.d;
	}
};

class MaxHeap{
public:
	 HeapNode *nodes;
	 int nextPlace;
	 int maxNumber;
	 MaxHeap(int n){
		maxNumber = pow((double)2,(double)n);
		nextPlace = 1;//下一个存放位置
		nodes = new HeapNode[maxNumber];
	}
	 MaxHeap(){
	 }
    void put(HeapNode node){
		nodes[nextPlace] = node;
		nextPlace++;
		heapSort(nodes);
	}
	HeapNode removeMax(){
		HeapNode tempNode = nodes[1];
		nextPlace--;
		nodes[1] = nodes[nextPlace];
		heapSort(nodes);
		return tempNode;
	}
	 void heapAdjust(HeapNode *  nodes,int s,int m){
		HeapNode rc = nodes[s];
		for(int j=2*s;j<=m;j*=2){
			if(j<m&&nodes[j].upperProfit<nodes[j+1].upperProfit)
				++j;
			if(!(rc.upperProfit<nodes[j].upperProfit))
				break;
			nodes[s] = nodes[j];
			s = j;
		}
		nodes[s] = rc;
	}
    void heapSort(HeapNode * nodes){
		for(int i=(nextPlace-1)/2;i>0;--i){
			heapAdjust(nodes,i,nextPlace-1);
		}
	}
} ;


#endif
2.测试代码

#include <iostream>
using namespace std;



//子空间中节点类型
#include "beibao.h"


double c=30; 
const int n=3;
double *w;
double *p;
double cw;
double cp;
int    *bestX;
MaxHeap * heap;


//上界函数bound计算结点所相应价值的上界
 double bound(int i){
	double cleft=c-cw;
	double b=cp;
	while(i<=n&&w[i]<=cleft){
		cleft=cleft-w[i];
		b=b+p[i];
		i++;
	}
	//装填剩余容量装满背包
	if(i<=n)
		b=b+p[i]/w[i]*cleft;
	return b;
}
//addLiveNode将一个新的活结点插入到子集树和优先队列中
 void addLiveNode(double up,double pp,double ww,int lev,BBnode* par,bool ch){
	//将一个新的活结点插入到子集树和最大堆中
	BBnode *b=new BBnode(par,ch);
	HeapNode  node =HeapNode(b,up,pp,ww,lev);
	heap->put(node);
}
 double MaxKnapsack(){
	//优先队列式分支限界法,返回最大价值,bestx返回最优解
	BBnode * enode=new BBnode();
	int i=1;
	double bestp=0;//当前最优值
	double up=bound(1);//当前上界
	while(i!=n+1){//非叶子结点
		//检查当前扩展结点的左儿子子结点
		double wt=cw+w[i];
		if(wt<=c){
			if(cp+p[i]>bestp)
				bestp=cp+p[i];
			addLiveNode(up,cp+p[i],cw+w[i],i+1,enode,true);
		}
		up=bound(i+1);
		if(up>=bestp)
			addLiveNode(up,cp,cw,i+1,enode,false);
		HeapNode node =heap->removeMax();
		enode=node.liveNode;
		cw=node.weight;
		cp=node.profit;
		up=node.upperProfit;
		i=node.level;
	}
	for(int j=n;j>0;j--){

		bestX[j]=(enode->leftChild)?1:0;
		enode=enode->parent;
	}
	return cp;
}


 double knapsack(double *pp,double *ww,double cc,int *xx){
	//返回最大值,bestX返回最优解
	c=cc;
	//n=sizeof(pp)/sizeof(double);
	//定义以单位重量价值排序的物品数组
	Element *q=new Element[n];
	double ws=0.0;
	double ps=0.0;
	for(int i=0;i<n;i++){
		q[i]=Element(i+1,pp[i+1]/ww[i+1]);
		ps=ps+pp[i+1];
		ws=ws+ww[i+1];
	}
	if(ws<=c){
		return  ps;
	}           
	p=new double[n+1];
	w=new double[n+1];
	for(int i=0;i<n;i++){
		p[i+1]=pp[q[i].id];
		w[i+1]=ww[q[i].id];
	}
	cw=0.0;
	cp=0.0;
	bestX = new int[n+1];
	heap = new MaxHeap(n);
	double bestp = MaxKnapsack();
	for(int j=0;j<n;j++)
		xx[q[j].id]=bestX[j+1];

	return  bestp;

}




void main(){
	
	w=new double[4];
	w[1]=16;w[2]=15;w[3]=15;
	p=new double[4];
	p[1]=45;p[2]=25;p[3]=25;
	int *x = new int[4];
	double m = knapsack(p,w,c,x);


	cout<<"*****分支限界法*****"<<endl;
	cout<<"*****物品个数:n="<<n<<endl;
	cout<<"*****背包容量:c="<<c<<endl;
	cout<<"*****物品重量数组:w= {"<<w[3]<<" "<<w[1]<<" "<<w[2]<<"}"<<endl;
	cout<<"*****物品价值数组:v= {"<<p[3]<<" "<<p[1]<<" "<<p[2]<<"}"<<endl;
	cout<<"*****最优值:="<<m<<endl;
	cout<<"*****选中的物品是:";
	for(int i=1;i<=3;i++)
		cout<<x[i]<<" ";
	cout<<endl;
}





3.测试结果:

*****分支限界法*****
*****物品个数:n=3
*****背包容量:c=30
*****物品重量数组:w= {15 16 15}
*****物品价值数组:v= {25 45 25}
*****最优值:=50
*****选中的物品是:0 1 1




  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用分支限界法求解0/1背包问题C++代码: ```cpp #include <iostream> #include <algorithm> #include <queue> #include <vector> using namespace std; struct Node { int level; int profit; int weight; double bound; }; bool operator<(const Node& a, const Node& b) { return a.bound < b.bound; } double bound(Node u, int n, int W, vector<pair<int, int>>& items) { if (u.weight >= W) { return 0; } double profitBound = u.profit; int j = u.level + 1; int totalWeight = u.weight; while ((j < n) && (totalWeight + items[j].second <= W)) { totalWeight += items[j].second; profitBound += items[j].first; j++; } if (j < n) { profitBound += (W - totalWeight) * (double)items[j].first / items[j].second; } return profitBound; } int knapsack(int n, int W, vector<pair<int, int>>& items) { priority_queue<Node> pq; Node u, v; pq.push({-1, 0, 0, 0}); int maxProfit = 0; while (!pq.empty()) { u = pq.top(); pq.pop(); if (u.level == n - 1) { continue; } v.level = u.level + 1; v.weight = u.weight + items[v.level].second; v.profit = u.profit + items[v.level].first; if (v.weight <= W && v.profit > maxProfit) { maxProfit = v.profit; } v.bound = bound(v, n, W, items); if (v.bound > maxProfit) { pq.push(v); } v.weight = u.weight; v.profit = u.profit; v.bound = bound(v, n, W, items); if (v.bound > maxProfit) { pq.push(v); } } return maxProfit; } int main() { int n = 4; int W = 10; vector<pair<int, int>> items = {{40, 2}, {30, 5}, {50, 10}, {10, 5}}; int result = knapsack(n, W, items); cout << "Maximum profit: " << result << endl; return 0; } ``` 在上面的代码中,我们首先定义了一个结构体`Node`,其中包含了四个成员变量`level`、`profit`、`weight`和`bound`,分别表示当前节点在决策树中的层数、当前的利润、当前的重量和当前节点的上界。另外,我们还定义了一个小于号运算符,用于将结构体按照上界从小到大排序。 然后,我们定义了一个`bound`函数,用于计算当前节点的上界。在计算上界的过程中,我们首先判断当前节点的重量是否超出了背包的容量,如果是的话,直接返回0。否则,我们将当前节点的利润作为上界的初始值,然后从当前节点的下一个节点开始,依次加入物品,直到背包装满或者物品加完为止。如果还有剩余的空间,我们按照单位重量的价值将剩余的物品加入背包,然后返回计算出的上界。 接下来,我们定义了一个`knapsack`函数,用于求解0/1背包问题。在函数中,我们首先定义了一个优先队列`pq`,用于保存当前还未扩展的节点。然后,我们将根节点加入队列中。之后,我们不断从队列中取出上界最小的节点并进行扩展,如果当前节点已经是叶子节点,则直接跳过。否则,我们分别计算出将当前节点的下一个节点加入背包和不加入背包的两种情况下的上界,并将对应的节点加入队列中。如果当前节点的上界已经小于已知的最大利润,则直接跳过。如果队列为空时,我们已经搜索完了整个决策树,此时的最大利润即为问题的解。 最后,我们在`main`函数中调用`knapsack`函数求解0/1背包问题,并输出结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值